# -*- coding: utf-8 -*-
import socket
import netifaces
import os

'''
交换机与控制器交互拓扑信息的通信模块
交换机到控制器存在稳定链路，故使用udp
'''


class TopoClient():
    def __init__(self, aim_IP, aim_port, ad_hoc_eth, break_IP=None, break_port=0, listen_port=0):
        self.aim_IP = aim_IP
        self.aim_port = aim_port
        self.ad_hoc_eth = ad_hoc_eth
        if break_IP and break_port:
            self.break_IP = break_IP
            self.break_port = break_port
            self.break_s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            self.update_topo = self.update_topo_break
        else:
            self.update_topo = self.update_topo_signle
        self.listen_port = aim_port if not listen_port else listen_port  # 默认监听端口和服务器端口一致
        self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.s.bind(('0.0.0.0', self.listen_port))
        self.IP = netifaces.ifaddresses(ad_hoc_eth).setdefault(
            netifaces.AF_INET)[0]['addr']  # 获取ad_hoc网口IP
        self.mac = netifaces.ifaddresses(
            ad_hoc_eth)[netifaces.AF_LINK][0]['addr']  # 获取ad_hoc网口mac

    def init(self, break_controller=False):
        '''
        初始化操作，将自身mac上传到服务器，如果使用静态mac方案务必调用
        '''
        if break_controller: # 从控制器的初始化过程
            s=self.break_s
            aim_IP = self.break_IP
            aim_port = self.break_port
        else:
            s=self.s
            aim_IP = self.aim_IP
            aim_port = self.aim_port
        data = ('%s %s 2' % (self.IP, self.mac)).encode(
            'utf-8')  # 初始化先通知控制器自身mac
        s.settimeout(5)  # 设置超时时间，如果服务器一直未响应则重新发送
        while True:
            s.sendto(data, (aim_IP, aim_port))
            try:
                s.recvfrom(1024)
            except:
                continue
            break
        s.settimeout(None)  # 取消超时

    def listen_mac(self):
        '''
        接收控制器发送来的其他节点的mac并写入本地arp表
        '''
        while True:
            data, _ = self.s.recvfrom(1024)
            ip, mac = data.decode('utf-8').split()
            os.system('arp -s %s -i %s %s' % (ip, self.ad_hoc_eth, mac))

    def update_topo_signle(self, new_connect, lost):
        '''
        更新链路状态到控制器，1代表新加入，0代表离开
        :param new_connect: 新的邻居
        :param lost: 断开的邻居
        :return:
        '''
        for n in new_connect:
            data = ('%s %s 1' % (self.IP, n)).encode('utf-8')
            self.s.sendto(data, (self.aim_IP, self.aim_port))
        for l in lost:
            data = ('%s %s 0' % (self.IP, l)).encode('utf-8')
            self.s.sendto(data, (self.aim_IP, self.aim_port))

    def update_topo_break(self, new_connect, lost):
        '''
        更新链路状态到控制器，和备用控制器，1代表新加入，0代表离开
        :param new_connect: 新的邻居
        :param lost: 断开的邻居
        :return:
        '''
        for n in new_connect:
            data = ('%s %s 1' % (self.IP, n)).encode('utf-8')
            self.s.sendto(data, (self.aim_IP, self.aim_port))
            self.break_s.sendto(data, (self.break_IP, self.break_port))
            print("send to %s %s"%(self.break_IP,self.break_port))
        for l in lost:
            data = ('%s %s 0' % (self.IP, l)).encode('utf-8')
            self.s.sendto(data, (self.aim_IP, self.aim_port))
            self.break_s.sendto(data, (self.break_IP, self.break_port))
